/*                                    _
 *   ___ _ __ ___ _ __ ___   ___   __| |
 *  / __| '__/ __| '_ ` _ \ / _ \ / _` |
 *  \__ \ |  \__ \ | | | | | (_) | (_| |
 *  |___/_|  |___/_| |_| |_|\___/ \__,_|     
 * 
 *    _|_ _  _ |    _  _ _ |. _ |_ _|_
 *     | (_|| ||<  |_)| (/_||(_|| | | 
 *           _ _  _| _|   | _ _|
 *          | | |(_)(_||_||(/_
 ******************************************
 ******************************************
 ******************************************
 * . _ _  _ | _  _ _  _  _ _|_ _ _|_. _  _ 
 * || | ||_)|(/_| | |(/_| | | (_| | |(_)| |
 *       |                                 
 *		
 *		Catches the Tank Spawn event, checks for the Tank to be AI controlled, 
 *		and if thats the case, temporally adds the GODMODE Flag to its entity.
 *		The AI Tank will now be invulnerable to Bullets. It also freezes him in Place.
 *		
 *		If its not an AI Tank (anymore), it starts a Timer after which the Tank
 *		is extinguished when on fire. This delay exists so a Player can leave a Molotov area 
 *		after taking control of the AI Tank.
 *
 *		Also adds a frustration bar replacement where L4D2 does not provide one.
 *		(culling tanks)
 */

#define MODULE_NAME "TankPrelight"

static const String:FLAGS_ENTPROP[]			= "m_fFlags";
static const String:FRUST_ENTPROP[]			= "m_frustration";
static const Float:AI_TANK_THAW_TIME 		= 5.0;
static const Float:HINT_BOX_REFRESH_TIME 	= 1.0;
static const		FRUSTRATION_FULL_AMOUNT	= 100;
static const		FLAG_GODMODE			= FL_GODMODE;
static const		FLAG_ONFIRE				= FL_ONFIRE;

static aiTankID								= 0; 		//Stores the client ID of the AI tank.
static bool:tankCulled						= false; 	//Records whether the last tank spawn was culled.
static bool:eventsHooked					= false;

static Handle:cvarTankFreezeEnabled			= INVALID_HANDLE;
static Handle:cvarTankFreezeTime			= INVALID_HANDLE;

public TankPrelight_OnModuleLoaded()
{
	cvarTankFreezeEnabled = 		CreateConVar("srs_tank_prelight_fix",		"1", 	"Enable anti-tank pre-light precautions.",											SRS_CVAR_DEFAULT_FLAGS);
	cvarTankFreezeTime = 			CreateConVar("srs_tank_immunity_time", 		"2.0", 	"Time that the tank has godmode/fire immunity after player control",				SRS_CVAR_DEFAULT_FLAGS);

	_TP_OnModuleEnabled(); // default ON
	HookConVarChange(cvarTankFreezeEnabled, _TP_FlipActivation);
}

public _TP_FlipActivation(Handle:convar, const String:oldValue[], const String:newValue[])
{
	if (ACTIVATION_FLIP_OFF_TO_ON)
	{
		_TP_OnModuleEnabled();
	}
	else if (ACTIVATION_FLIP_ON_TO_OFF)
	{
		_TP_OnModuleDisabled();
	}
}

static _TP_OnModuleEnabled()
{
	HookEvent("tank_spawn", _TP_TankSpawn_Event, EventHookMode_Post);
	HookEvent("tank_frustrated", _TP_TankFrustrated_Event, EventHookMode_PostNoCopy);
	eventsHooked = true;
}

static _TP_OnModuleDisabled()
{
	if (!IsPluginEnding() && eventsHooked)
	{
		UnhookEvent("tank_spawn", _TP_TankSpawn_Event, EventHookMode_Post);
		UnhookEvent("tank_frustrated", _TP_TankFrustrated_Event, EventHookMode_PostNoCopy);
		eventsHooked = false;
	}
}

// Don't let AI tank throw rocks
public TankPrelight_OnPlayerRunCmd(client, &buttons)
{
	if (aiTankID && client == aiTankID && IsFakeClient(aiTankID) && IsValidTank(aiTankID))
	{
		Debug_PrintSpam("Prevented AI %N from throwing rocks", client);
		buttons &= ~IN_ATTACK2;
	}
}

public Action:_TP_TankSpawn_Event(Handle:event, const String:name[], bool:dontBroadcast)
{
	if (!GetConVarInt(cvarTankFreezeEnabled) || !IsAllowedGameMode())
	{
		return;
	}
	new tankClient = GetEventInt(event, "tankid");
	Debug_Print("  BS_TankSpawn");
	if (IsFakeClient(tankClient) && !tankCulled) //If it's AI freeze it for 5 seconds (as opposed to forever, which wouldn't work in coop)
	{
		Debug_Print("AI Tank Spawned");
		SetEntityMoveType(tankClient, MOVETYPE_NONE);
		SetEntProp(tankClient, Prop_Data, FLAGS_ENTPROP, GetEntProp(tankClient, Prop_Data, FLAGS_ENTPROP) | FLAG_GODMODE);
		CreateTimer(AI_TANK_THAW_TIME, _TP_ThawAI_Timer);
		aiTankID = tankClient;
		return;
	}
	if (!IsFakeClient(tankClient) && !tankCulled) //If it's human, remove the freeze timer, and start a countdown to extinguish the tank
	{
		Debug_Print("Tank now has human control");
		new Handle:pack;
		SetEntProp(tankClient, Prop_Data, FLAGS_ENTPROP, GetEntProp(tankClient, Prop_Data, FLAGS_ENTPROP) | FLAG_GODMODE);
		CreateDataTimer(GetConVarFloat(cvarTankFreezeTime), _TP_Extinguish_DataTimer, pack);
		WritePackCell(pack, tankClient);
		SetEntityMoveType(tankClient, MOVETYPE_CUSTOM);
		aiTankID = 0; //Tank is no longer AI
		return;
	}
	Debug_Print("Tank was culled.");
	tankCulled = false;  //If neither of the 2 functions were called, the tank was passed for this spawn, so reset that variable.
}

public Action:_TP_TankFrustrated_Event(Handle:event, const String:name[], bool:dontBroadcast)
{
	Debug_Print("  BS_TankCull");
	tankCulled = true;
}

public Action:_TP_Extinguish_DataTimer(Handle:timer, Handle:pack) //extinguishes  a tank, and resets it's health
{
	Debug_Print("  BS_Extinguish");
	ResetPack(pack);
	new client = ReadPackCell(pack);
	RemoveGodmodeFromAllTanks();
	if (!IsClientInGame(client))
	{
		return;
	}
	if (GetEntProp(client, Prop_Data, FLAGS_ENTPROP) & FLAG_ONFIRE)
	{
		Debug_Print("Starting hint text on client %N", client);
		CreateTimer(HINT_BOX_REFRESH_TIME, _TP_TankControlHintText_Timer, client, TIMER_REPEAT);
	}
	ExtinguishEntity(client);
}

public Action:_TP_ThawAI_Timer(Handle:timer) //Thaws an AI tank, it will only fire after 5 seconds which means it was not passed to a player.  Either because of no player infected, or being passed to AI
{
	if (!aiTankID || !IsValidTank(aiTankID) || !IsFakeClient(aiTankID))
	{
		aiTankID = 0;
		Debug_Print("Thaw AI aborted");
		return Plugin_Stop;
	}
	Debug_Print("  BS_ThawAI");
	RemoveGodmodeFromAllTanks();
	if (IsValidEntity(aiTankID))
	{
		SetEntityMoveType(aiTankID, MOVETYPE_CUSTOM);
	}
	aiTankID = 0; //We no longer need this variable
	return Plugin_Handled;
}

public Action:_TP_TankControlHintText_Timer(Handle:hTimer, any:tankClient) //This displays a fake tank control meter if the tank lost the original one
{
	if (!IsValidTank(tankClient) || GetEntProp(tankClient, Prop_Data, FLAGS_ENTPROP) & FLAG_ONFIRE)
	{
		Debug_Print("Tank is no longer client %N, stopping hint text", tankClient);
		return Plugin_Stop;
	}
	PrintHintText(tankClient, "%t %d", "TankControl", (FRUSTRATION_FULL_AMOUNT - GetEntProp(tankClient, Prop_Send, FRUST_ENTPROP)));
	return Plugin_Continue;
}

static RemoveGodmodeFromAllTanks()
{
	FOR_EACH_INFECTED(i)
	{
		if (L4D2_GetClientClass(i) == L4D2Class_Tank)
		{
			SetEntProp(i, Prop_Data, FLAGS_ENTPROP, GetEntProp(i, Prop_Data, FLAGS_ENTPROP) & ~FLAG_GODMODE);
			Debug_Print("Found tank %N, removing godmode", i);
		}
		else
		{
			Debug_Print("Found SI Class %d on %N, skipping.", L4D2_GetClientClass(i), i);
		}
	}
}

static bool:IsValidTank(client)
{
	return (IsClientInGame(client) && L4D2_GetClientClass(client) == L4D2Class_Tank && IsPlayerAlive(client));
}

#undef MODULE_NAME
